#include "Live555MediaControl.h"
#include "ourRTSPClient.h"

#ifndef INT64_MAX
#define INT64_MAX        9223372036854775807i64
#endif

static bool wait_Live555_response( RTSPClient *rtspClient);
static void default_live555_callback( RTSPClient *rtspClient, int result_code, char* result_string );

Live555MediaControl::Live555MediaControl()
{
	scheduler		= NULL;
	environment		= NULL;

	rtspClient		= NULL;
	mediaSession	= NULL;
	mediaSubSession	= NULL; 

	f_npt			= 0.0;
	f_npt_length	= 0.0;
	f_npt_start		= 0.0;

	event_rtsp		= 0;

	b_paused		= false;;   /* Are we paused? */
	b_error			= false;;
	i_live555_ret	= 0;;		/* live555 callback return code */

	f_seek_request	= 0.0;		/* In case we receive a seek request while paused*/
}

int Live555MediaControl::seek(int64_t time_us)
{
	if( rtspClient && (f_npt_length > 0) )
	{
		float time;

		if( f_npt > 0) {
			time = (float)(time_us / 1000000.0); /* in second */
		}
		else {
			return VLC_EGENERIC;
		}

		/* if paused, just set time */
		if( b_paused ) {
			f_seek_request = time;
			return VLC_SUCCESS;
		}

		rtspClient->sendPauseCommand( *mediaSession, default_live555_callback, NULL );

		if( !wait_Live555_response( rtspClient) )
		{
			msg_Err( p_demux, "PAUSE before seek failed %s",
				env->getResultMsg() );
			return VLC_EGENERIC;
		}

		rtspClient->sendPlayCommand( *mediaSession, default_live555_callback, time, -1, 1 );

		if( !wait_Live555_response( rtspClient) )
		{
			msg_Err( p_demux, "seek PLAY failed %s",
				env->getResultMsg() );
			return VLC_EGENERIC;
		}

		/* Retrieve the starttime if possible */
		f_npt = f_npt_start = mediaSession->playStartTime();

		/* Retrieve the duration if possible */
		if( mediaSession->playEndTime() > 0 )
			f_npt_length = mediaSession->playEndTime();

		msg_Dbg( p_demux, "seek start: %f stop:%f", f_npt_start, f_npt_length );
		return VLC_SUCCESS;
	}
	return VLC_EGENERIC;
}

int Live555MediaControl::getCurrTime(int64_t* time_us) 
{
	if( f_npt > 0 )
	{
		*time_us = (int64_t)(f_npt * 1000000.);
		return VLC_SUCCESS;
	}
	return VLC_EGENERIC;
}

int Live555MediaControl::getTotalTime(int64_t* time_us)
{
	if( f_npt_length > 0 )
	{
		double d_length = f_npt_length * 1000000.0;
		if( d_length >= INT64_MAX )
			*time_us = INT64_MAX;
		else
			*time_us = (int64_t)d_length;
		return VLC_SUCCESS;
	}
	return VLC_EGENERIC;
}

int Live555MediaControl::pause(bool b_pause)
{
	if( rtspClient == NULL )
		return VLC_EGENERIC;

	if( b_pause == b_paused )
		return VLC_SUCCESS;
	if( b_pause )
		rtspClient->sendPauseCommand( *mediaSession, default_live555_callback );
	else
		rtspClient->sendPlayCommand( *mediaSession, default_live555_callback, f_seek_request, -1.0f, mediaSession->scale() );

	if( !wait_Live555_response( rtspClient ) )
	{
		msg_Err( p_demux, "PLAY or PAUSE failed %s", env->getResultMsg() );
		return VLC_EGENERIC;
	}
	f_seek_request = -1;
	b_paused = b_pause;

	/* TPADD20140311: Must send keep alive message to the server 
	to prevent the rtp server shutdown, refer function <Control_KeepAlive> */

	/* Retrieve the starttime if possible */
	f_npt_start = mediaSession->playStartTime();

	/* Retrieve the duration if possible */
	if( mediaSession->playEndTime() )
		f_npt_length = mediaSession->playEndTime();

	msg_Dbg( p_demux, "pause start: %f stop:%f", f_npt_start, f_npt_length );
	return VLC_SUCCESS;
}

int Live555MediaControl::keepAlive()
{
	char *psz_bye = NULL;
	rtspClient->sendGetParameterCommand( *mediaSession, NULL, psz_bye );
	return VLC_SUCCESS;
}

static void default_live555_callback(  RTSPClient *rtspClient, int result_code, char* result_string )
{
	ourRTSPClient* myClient = (ourRTSPClient*)rtspClient;
	delete []result_string;
	myClient->mediaControl->i_live555_ret = result_code;
	myClient->mediaControl->b_error = myClient->mediaControl->i_live555_ret != 0;
	myClient->mediaControl->event_rtsp = 1;
}

/* return true if the RTSP command succeeded */
static bool wait_Live555_response( RTSPClient *rtspClient)
{
	ourRTSPClient* myClient = (ourRTSPClient*)rtspClient;

	myClient->mediaControl->event_rtsp = 0;
	myClient->mediaControl->event_rtsp = 0;
	myClient->mediaControl->b_error = true;
	myClient->mediaControl->i_live555_ret = 0;
	myClient->mediaControl->scheduler->doEventLoop( & myClient->mediaControl->event_rtsp );

	return !myClient->mediaControl->b_error;
}
